Surface Temperature#

../../../_images/dcc0db54b3d9ec3c280e235d1e52ea0562f34d3cb7229d288b9ae84968c87bf4.png

Highlights

  • The Pacific Islands mean temperature over land increased by 1.1°C (2°F) since 1951, whereas in Palau, the records show an increase of 0.53 °C from 1951 to 2025.

  • On the other hand, the minimum temperatures show an increasing trend of 0.013 °C/year and the maximum temperatures a non signiticative trend of 0.001, making the variability of temperatures within each day to be decreasing at -0.01 °C/year.

  • The top 10 years on record have occurred since 2001.

Setup#

First, we need to import all the necessary libraries. Some of them are specifically developed to handle the download and plotting of the data and are hosted at the indicators set-up repository in GitHub

Hide code cell source
import warnings
warnings.filterwarnings("ignore")
Hide code cell source
import os.path as op
import sys
import contextlib

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from myst_nb import glue 

sys.path.append("../../../../indicators_setup")
from ind_setup.plotting_int import plot_timeseries_interactive, fig_int_to_glue
from ind_setup.plotting import plot_bar_probs, fontsize
from ind_setup.tables import get_data_metrics, plot_df_table

sys.path.append("../../../functions")
from data_downloaders import GHCN

Define location and variables of interest#

country = 'Palau'
vars_interest = ['TMIN', 'TMAX']

Get Data#

update_data = False
path_data = "../../../data"
path_figs = "../../../matrix_cc/figures"

Observations from Koror Station#

https://www.ncei.noaa.gov/data/global-historical-climatology-network-daily/doc/GHCND_documentation.pdf

The data used for this analysis comes from the GHCN (Global Historical Climatology Network)-Daily database.
This a database that addresses the critical need for historical daily temperature, precipitation, and snow records over global land areas. GHCN-Daily is a composite of climate records from numerous sources that were merged and then subjected to a suite of quality assurance reviews. The archive includes over 40 meteorological elements including temperature daily maximum/minimum, temperature at observation time, precipitation and more.

Hide code cell source
if update_data:
    df_country = GHCN.get_country_code(country)
    print(f'The GHCN code for {country} is {df_country["Code"].values[0]}')

    df_stations = GHCN.download_stations_info()
    df_country_stations = df_stations[df_stations['ID'].str.startswith(df_country.Code.values[0])]
    print(f'There are {df_country_stations.shape[0]} stations in {country}')
Hide code cell source
if update_data:
    GHCND_dir = 'https://www.ncei.noaa.gov/data/global-historical-climatology-network-daily/access/'
    id = 'PSW00040309' # Koror Station
    dict_min = GHCN.extract_dict_data_var(GHCND_dir, 'TMIN', df_country_stations.loc[df_country_stations['ID'] == id])[0][0]
    dict_max = GHCN.extract_dict_data_var(GHCND_dir, 'TMAX', df_country_stations.loc[df_country_stations['ID'] == id])[0][0]
    st_data = pd.concat([dict_min['data'], (dict_max['data'])], axis=1).dropna()
    st_data['diff'] = st_data['TMAX'] - st_data['TMIN']
    st_data['TMEAN'] = (st_data['TMAX'] + st_data['TMIN'])/2
    st_data.to_pickle(op.join(path_data, 'GHCN_surface_temperature.pkl'))
else:
    st_data = pd.read_pickle(op.join(path_data, 'GHCN_surface_temperature.pkl'))
st_data = st_data.resample('Y').mean()
glue("n_years", len(np.unique(st_data.index.year)), display=False)
glue("start_year", st_data.dropna().index[0].year, display=False)
glue("end_year", st_data.dropna().index[-1].year, display=False)

Mean temperature#

Plotting#

At this piece of code we will plot the Mean annual temperature over time and its associated trend

dict_plot = [{'data' : st_data, 'var' : 'TMEAN', 'ax' : 1, 'label' : 'TMEAN'},
        ]
dict_plot = [{'data' : st_data, 'var' : 'TMEAN', 'ax' : 1, 'label' : 'TMEAN'}]
fig = plot_timeseries_interactive(dict_plot, trendline=True, figsize = (25, 12))

glue("trend_fig_mean", fig_int_to_glue(fig), display=False)

Fig. Annual maxima corresponding to the mean temperature.

Here we are creating a new column with the information of the temperature refered to the climatology of 1960 to 1990

st_data['TMEAN_ref'] = st_data['TMEAN'] - st_data.loc['1961':'1990'].TMEAN.mean()
# import matplotlib.pyplot as plt
# plot_bar_probs(x = st_data.index.year, y = st_data.TMEAN_ref, trendline = True, figsize = [15, 4])
# plt.title('Temperature anomalies (Over and above 1961 - 1990 reference period)', fontsize = 15);
nevents = 10
top_10 = st_data.sort_values(by='TMEAN_ref', ascending=False).head(nevents)
from ind_setup.tables import plot_df_table

var = 'TMEAN'
df = get_data_metrics(st_data, var, )
fig = plot_df_table(df.T, figsize = (300, 400))
../../../_images/04da2b50be25fd6bc2651c9ea68d79838379b2cba218e8bcdabf5c1456a52779.png

The following bar plot represents the mean temperature anomalies with respect to the 1960-1990 climatology along with the 10 largest temperature events in the record

fig, ax, trend = plot_bar_probs(x=st_data.index.year, y=st_data.TMEAN_ref, trendline=True,
                                y_label='Mean Temperature [°C]', figsize=[15, 4], return_trend=True)

glue("trend_mean", float(trend), display=False)
glue("change_mean", float(trend * len(np.unique(st_data.index.year))), display=False)
glue("top_10_year", float(top_10.sort_index().index.year[0]), display=False)

im = ax.scatter(top_10.index.year, top_10.TMEAN_ref, 
                c=top_10.TMEAN_ref.values, s=100, cmap='rainbow', label='Top 10 warmest years')
plt.title('Temperature anomalies (Over and above 1961 - 1990 reference period)', fontsize=15)
plt.colorbar(im).set_label('Mean Temperature [°C]', fontsize=fontsize)
glue("trend_fig", fig, display=False)
../../../_images/60e5ace910c044ef1f9047902370bd2edf1b62b9accb37b12cae73eef60941f5.png

Fig. 1 Annomaly of the mean temperature over and above the 1961-1990 reference period. Overlapping points correspond to the top 10 warmer years.#

Minimum and Maximum Temperatures#

The following plot represent the average minimum and maximum temperature over time

dict_plot = [{'data' : st_data, 'var' : 'TMIN', 'ax' : 1, 'label' : 'TMIN'},
        {'data' : st_data, 'var' : 'TMAX', 'ax' : 2, 'label' : 'TMAX'},
        # {'data' : st_data, 'var' : 'diff', 'ax' : 1, 'label' : 'Difference TMAX - TMIN'}
        ]
fig, TRENDS = plot_timeseries_interactive(dict_plot, trendline=True, figsize = (24, 11), return_trend = True)
fig.write_html(op.join(path_figs, 'F3_ST_min_max.html'), include_plotlyjs="cdn")

glue("trend_min", float(TRENDS[0]), display=False)
glue("trend_max", float(TRENDS[1]), display=False)

glue("change_min", float(TRENDS[0]*len(np.unique(st_data.index.year))), display=False)
glue("change_max", float(TRENDS[1]*len(np.unique(st_data.index.year))), display=False)

glue("trend_fig_max_min", fig_int_to_glue(fig), display=False)

Fig. Annual maximum (red) and minimum (blue) temperature at Koror. The solid black line represents the trend, which is statistically significant (p < 0.05). The dashed black line represents a trend that is not statistically significant.

Generate table#

The final step is to generate a table sumarizing different metrics of the data analyzed in the plots above

var = 'TMIN'
df = get_data_metrics(st_data, var, )
fig = plot_df_table(df.T, figsize = (300, 400))
../../../_images/09f2e41f1ae99b5eaa58ff05259526e7a65ce03fbad230021259181b3534b1ee.png
var = 'TMAX'
df = get_data_metrics(st_data, var, )
fig = plot_df_table(df.T, figsize = (300, 400))
../../../_images/c123147bf3d3678b1778a72c992f0e98ac08e2513eda6772f8c90c4297109d5c.png

Difference temperature#

The following plot represents the avergae difference between the minimum and maximum temperature over time. The decreasing trend means that the daily variability is decreasing over time

dict_plot = [{'data' : st_data, 'var' : 'diff', 'ax' : 1, 'label' : 'Difference TMAX - TMIN'}]
fig, trend = plot_timeseries_interactive(dict_plot, trendline=True, figsize = (25, 12), return_trend = True)
glue("trend_diff", float(trend[0]), display=False)

Fig. Annual maximum of the difference of the maximum and minimum temperature within each day

Generate table#

The final step is to generate a table sumarizing different metrics of the data analyzed in the plots above

var = 'diff'
df = get_data_metrics(st_data, var, )
fig = plot_df_table(df.T, figsize = (300, 400))
../../../_images/50ec18804c82861d7b907338da1985addd35d69e2bc602dc3073020fe88c418b.png